package com.cy.pj.sys.service.realm;



import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.cy.pj.common.util.ShiroUtils;
import com.cy.pj.sys.dao.SysMenuDao;
import com.cy.pj.sys.dao.SysRoleMenuDao;
import com.cy.pj.sys.dao.SysUserDao;
import com.cy.pj.sys.dao.SysUserRoleDao;
import com.cy.pj.sys.pojo.SysUser;

//@Component
public class ShiroUserRealm extends AuthorizingRealm {
	@Autowired
	private SysUserDao sysUserDao;
	@Autowired
	private SysUserRoleDao sysUserRoleDao;
	@Autowired
	private SysRoleMenuDao sysRoleMenuDao;
	@Autowired
	private SysMenuDao sysMenuDao;
	/**负责授权信息的获取和封装
	 * FAQ? 如何获取用户的权限信息?
	 * 1)方案1:业务层单表查询?(查用户角色关系表,查角色菜单关系表,查菜单表)
	 * 2)方案2:表关联查询(用户角色关系表join角色菜单关系表join菜单表)
	 * select m.permission
	 * from sys_user_roles ur join sys_role_menus rm join sys_menus m
	 * on ur.role_id=rm.role_id and rm.menu_id=m.id
	 * where ....
	 * */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		System.out.println("==doGetAuthorizationInfo===");
		//1.获取登录用户的权限标识
		SysUser user=ShiroUtils.getUser();
		List<String> permissions=sysMenuDao.findUserPermissions(user.getId());
		//2.封装查询结果并返回
		Set<String> stringPermissions=new HashSet<>();//会自动对集合内容进行去重操作
		for(String per:permissions) {
			if(per!=null&&!"".equals(per)) {//!StringUtils.isEmpty(per)
				stringPermissions.add(per);
			}
		}
		System.out.println("stringPermissions="+stringPermissions);
		SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
		info.setStringPermissions(stringPermissions);
		return info;
	}
//	@Override
//	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//		System.out.println("==doGetAuthorizationInfo===");
//		//1.获取登录用户
//		SysUser user=(SysUser)principals.getPrimaryPrincipal();//获取登录用户身份
//		//2.基于用户id查询角色id并校验
//		List<Integer> roleIds=sysUserRoleDao.findRoleIdsByUserId(user.getId());
//		if(roleIds==null||roleIds.size()==0)
//			throw new AuthorizationException();
//		//3.基于角色id查询菜单id并校验
//		List<Integer> menuIds=sysRoleMenuDao.findMenuIdsByRoleIds(roleIds);
//		if(menuIds==null||menuIds.size()==0)
//			throw new AuthorizationException();
//		//4.基于菜单id查询授权标识并校验
//		List<String> permissions=sysMenuDao.findPermissions(menuIds);
//		if(permissions==null||permissions.size()==0)
//			throw new AuthorizationException();
//		//5.封装查询结果并返回
//		Set<String> stringPermissions=new HashSet<>();//会自动对集合内容进行去重操作
//		for(String per:permissions) {
//			if(per!=null&&!"".equals(per)) {//!StringUtils.isEmpty(per)
//				stringPermissions.add(per);
//			}
//		}
//		System.out.println("stringPermissions="+stringPermissions);
//		SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
//		info.setStringPermissions(stringPermissions);
//		return info;
//	}
	
    /**负责认证信息的获取和封装*/
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		//1.获取登录时输入的账号信息(可以从token中获取)
		UsernamePasswordToken uToken=(UsernamePasswordToken)token;
		String username=uToken.getUsername();//登录时输入的用户名
		//2.基于用户查找用户信息并校验
		SysUser user=sysUserDao.findUserByUserName(username);
		if(user==null)throw new UnknownAccountException();
		//3.判定用户是否锁定(禁用)
		if(user.getValid()==0)throw new LockedAccountException();
		//4.封装用户信息并返回.
		ByteSource credentialsSalt=ByteSource.Util.bytes(user.getSalt());
		SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(
				user,//principal 用户身份
				user.getPassword(),//hashedCredentials 数据库的密码(已加密)
				credentialsSalt, //credentialsSalt 盐
				getName());//realmName
		return info;//返回给securityManager
	}
	/**	负责构建凭证匹配器(密码加密策略)并返回,也可以重写对应的set方法
	 * 	认证时要对认证密码(登录时输入的密码)进行加密,加密策略应该与存入数据库的密码加密策略相同.
	 * */
//	@Override
//	public CredentialsMatcher getCredentialsMatcher() {
//		HashedCredentialsMatcher cMatcher=new HashedCredentialsMatcher();
//		cMatcher.setHashAlgorithmName("MD5");
//		cMatcher.setHashIterations(1);
//		return cMatcher;
//	}
	
	@Override
	public void setCredentialsMatcher(
	      CredentialsMatcher credentialsMatcher) {
		//构建凭证匹配对象 
		HashedCredentialsMatcher cMatcher=
		new HashedCredentialsMatcher();
		//设置加密算法
		cMatcher.setHashAlgorithmName("MD5");
		//设置加密次数
		cMatcher.setHashIterations(1);
		super.setCredentialsMatcher(cMatcher);
	}

}
